package ui;

import org.json.simple.JSONArray;
import org.json.simple.JSONValue;
import word.Word;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SwingConstants;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;

/**
 * 단어입력 대화상자
 */
public class MainFrame extends JFrame
{
	private final JTextField edit_name;       // 단어 입력창
	private final JTextField edit_mean;       // 의미 입력창
	private final WordListView wordListView;  // 단어 리스트뷰
	private final JComboBox wordTypeComboBox; // 품사선택 콤보박스

	private final Word.Type[] types; // 타입목록

	private String filePath; // 저장할 파일경로
	private final JFileChooser chooser; // 파일 열기/저장 대화상자

	/**
	 * 생성자
	 */
	public MainFrame()
	{
		super("단어장");

		chooser = new JFileChooser();
		chooser.setFileFilter(new FileNameExtensionFilter("단어장 파일 (*.voca)", "voca"));
		chooser.setMultiSelectionEnabled(false);

		setLayout(new BorderLayout());

		// 메뉴를 초기화한다.
		JMenuBar menuBar = new JMenuBar();
		add(menuBar, BorderLayout.NORTH);

		// 파일메뉴에 이름과 단축키를 부여한다.
		JMenu menu_file = new JMenu("파일(F)");
		menu_file.setMnemonic(KeyEvent.VK_F);
		menuBar.add(menu_file);

		// 신규메뉴에 이름과 단축키를 부여하고 파일메뉴 하위에 추가한다.
		JMenuItem menu_file_new = new JMenuItem("신규(N)");
		menu_file_new.setMnemonic(KeyEvent.VK_N);
		menu_file_new.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, KeyEvent.CTRL_DOWN_MASK));
		menu_file_new.addActionListener(new ActionListener()
		{
			/**
			 * 신규메뉴를 눌렀을 때 호출되는 메서드
			 * @param e : 이벤트에 대한 정보
			 */
			@Override
			public void actionPerformed(ActionEvent e)
			{
				// 파일저장 대화상자를 열고 저장버튼을 눌렀으면
				if (chooser.showSaveDialog(MainFrame.this) == JFileChooser.APPROVE_OPTION)
				{
					// 선택된 파일명과 경로명을 가져온다.
					filePath = chooser.getSelectedFile().getPath() + ".voca";

					// 단어 목록을 비운다.
					wordListView.removeAllWord();
					save();
				}
			}
		});
		menu_file.add(menu_file_new);

		// 열기메뉴에 이름과 단축키를 부여하고 파일메뉴 하위에 추가한다.
		JMenuItem menu_file_open = new JMenuItem("열기(O)");
		menu_file_open.setMnemonic(KeyEvent.VK_O);
		menu_file_open.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.CTRL_DOWN_MASK));
		menu_file_open.addActionListener(new ActionListener()
		{
			/**
			 * 열기메뉴를 눌렀을 때 호출되는 메서드
			 * @param e : 이벤트에 대한 정보
			 */
			@Override
			public void actionPerformed(ActionEvent e)
			{
				// 파일열기 대화상자를 열고 열기버튼을 눌렀으면
				if (chooser.showOpenDialog(MainFrame.this) == JFileChooser.APPROVE_OPTION)
				{
					// 사용자가 선택한 파일명 가져오고
					filePath = chooser.getSelectedFile().getPath();

					// 단어 목록을 비운다.
					wordListView.removeAllWord();
//					open(); // TODO 파일 여는 코드

					try
					{
						// 파일 입력 스트림을 열고 저장하고 닫는다.
						BufferedReader reader = new BufferedReader(new FileReader(filePath));
						String data = reader.readLine();
						JSONArray array = (JSONArray) JSONValue.parse(data);
						for (int i = 0; i < array.size(); i++)
						{
							Word word = Word.parseJSON((JSONArray) array.get(i));
							if (word != null)
								wordListView.addWord(word);
						}
						reader.close();
					}
					catch (IOException e1)
					{
					}
				}
			}
		});
		menu_file.add(menu_file_open);

		// 저장메뉴에 이름과 단축키를 부여하고 파일메뉴 하위에 추가한다.
		JMenuItem menu_file_save = new JMenuItem("저장(S)");
		menu_file_save.setMnemonic(KeyEvent.VK_S);
		menu_file_save.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_DOWN_MASK));
		menu_file_save.addActionListener(new ActionListener()
		{
			/**
			 * 저장메뉴를 눌렀을 때 호출되는 메서드
			 * @param e : 이벤트에 대한 정보
			 */
			@Override
			public void actionPerformed(ActionEvent e)
			{
				// 저장한다.
				save();
			}
		});
		menu_file.add(menu_file_save);

		// 종료메뉴에 이름과 단축키를 부여하고 파일메뉴 하위에 추가한다.
		JMenuItem menu_file_quit = new JMenuItem("종료(E)");
		menu_file_quit.setMnemonic(KeyEvent.VK_E);
		menu_file_quit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F4, KeyEvent.ALT_DOWN_MASK));
		menu_file_quit.addActionListener(new ActionListener()
		{
			/**
			 * 종료메뉴를 눌렀을 때 호출되는 메서드
			 * @param e : 이벤트에 대한 정보
			 */
			@Override
			public void actionPerformed(ActionEvent e)
			{
				// 프로그램을 닫는다.
				dispose();
			}
		});
		menu_file.add(menu_file_quit);

		// 도움말메뉴에 이름과 단축키를 부여한다.
		JMenu menu_help = new JMenu("도움말(H)");
		menu_help.setMnemonic(KeyEvent.VK_H);
		menuBar.add(menu_help);

		// 단어장 정보메뉴에 이름과 단축키를 부여하고 시험메뉴 하위에 추가한다.
		JMenuItem menu_help_about = new JMenuItem("단어장 정보(A)");
		menu_help_about.setMnemonic(KeyEvent.VK_A);
		menu_help_about.addActionListener(new ActionListener()
		{
			/**
			 * 단어장 정보메뉴를 눌렀을 때 호출되는 메서드
			 * @param e : 이벤트에 대한 정보
			 */
			@Override
			public void actionPerformed(ActionEvent e)
			{
				// 단어장 정보 대화상자를 띄운다.
				new AboutProgramDialog(MainFrame.this);
			}
		});
		menu_help.add(menu_help_about);

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

		JPanel contents = new JPanel();
		contents.setLayout(null);
		add(contents, BorderLayout.CENTER);

		// 데이터목록 (텍스트)
		JLabel txt_dataList = new JLabel("데이터 목록");
		txt_dataList.setBounds(15, 15, 100, 20);
		contents.add(txt_dataList);

		// 데이터편집 (텍스트)
		JLabel txt_editData = new JLabel("데이터 편집");
		txt_editData.setBounds(15, 265, 100, 20);
		contents.add(txt_editData);

		// 종류 (텍스트)
		JLabel txt_type = new JLabel("종류 : ");
		txt_type.setBounds(10, 295, 100, 20);
		txt_type.setFont(new Font(txt_type.getFont().getName(), Font.PLAIN, 12));
		contents.add(txt_type);

		// 단어 (텍스트)
		JLabel txt_word = new JLabel("단어 : ");
		txt_word.setBounds(10, 330, 100, 20);
		txt_word.setFont(new Font(txt_word.getFont().getName(), Font.PLAIN, 12));
		contents.add(txt_word);

		// 의미 (텍스트)
		JLabel txt_mean = new JLabel("의미 : ");
		txt_mean.setBounds(10, 365, 100, 20);
		txt_mean.setFont(new Font(txt_mean.getFont().getName(), Font.PLAIN, 12));
		contents.add(txt_mean);

		// 품사선택 콤보박스
		types = Word.Type.values();
		String[] typeList = new String[types.length];
		for (int i = 0; i < types.length; i++)
			typeList[i] = types[i].name;
		wordTypeComboBox = new JComboBox(typeList);
		wordTypeComboBox.setBounds(55, 295, 200, 20);

		contents.add(wordTypeComboBox);

		// 항목추가 버튼
		JButton addWordButton = new JButton("항목추가");
		addWordButton.setBounds(270, 330, 80, 20);
		addWordButton.setFont(new Font(addWordButton.getFont().getName(), Font.PLAIN, 11));
		addWordButton.addActionListener(new ActionListener()
		{
			/**
			 * 항목추가 버튼이 눌렸을 때 호출되는 메서드
			 * @param e : 이벤트에 대한 정보
			 */
			@Override
			public void actionPerformed(ActionEvent e)
			{
				// 사용자가 입력한 정보를 읽어오고
				Word.Type type = types[wordTypeComboBox.getSelectedIndex()];
				String name = edit_name.getText();
				String mean = edit_mean.getText();

				// 정보가 비어있지 않으면
				if (!name.equals("") && !mean.equals(""))
				{
					// 리스트에 추가한다.
					Word word = new Word(type, name, mean);
					word.addAttributes(AttributeDialog.attributes);
					wordListView.addWord(word);
				}
				AttributeDialog.attributes.clear();
			}
		});
		contents.add(addWordButton);

		// 항목삭제 버튼
		JButton removeWordButton = new JButton("항목삭제");
		removeWordButton.setBounds(270, 365, 80, 20);
		removeWordButton.setFont(new Font(removeWordButton.getFont().getName(), Font.PLAIN, 11));
		removeWordButton.addActionListener(new ActionListener()
		{
			/**
			 * 항목삭제 버튼이 눌렸을 때 호출되는 메서드
			 * @param e : 이벤트에 대한 정보
			 */
			@Override
			public void actionPerformed(ActionEvent e)
			{
				wordListView.removeAllSelectedWord();
			}
		});
		contents.add(removeWordButton);

		// + 버튼
		JButton plusButton = new JButton("+");
		plusButton.setBounds(125, 400, 50, 25);
		plusButton.setFont(new Font(plusButton.getFont().getName(), Font.BOLD, 14));
		plusButton.addActionListener(new ActionListener()
		{
			@Override
			public void actionPerformed(ActionEvent e)
			{
				AttributeDialog dialog = new AttributeDialog(MainFrame.this);
			}
		});
		contents.add(plusButton);

		// 단어이름 입력창
		edit_name = new JTextField();
		edit_name.setBounds(55, 331, 200, 20);
		contents.add(edit_name);

		// 단어의미 입력창
		edit_mean = new JTextField();
		edit_mean.setBounds(55, 366, 200, 20);
		contents.add(edit_mean);

		// 단어 리스트뷰
		wordListView = new WordListView();
		wordListView.setBorder(BorderFactory.createLineBorder(Color.gray));
		wordListView.setBounds(10, 45, 340, 190);
		contents.add(wordListView);

		// 구분선
		JSeparator separator = new JSeparator();
		separator.setBounds(6, 250, 347, 1);
		contents.add(separator);

		setDefaultCloseOperation(DISPOSE_ON_CLOSE);
		setSize(365, 490);
		setLocationRelativeTo(null);
		setResizable(false);
		setVisible(true);
	}

	/**
	 * 저장하는 메서드
	 */
	private void save()
	{
		// 파일경로가 정해져 있으면
		if (filePath != null)
		{
			try
			{
				// 파일 출력 스트림을 열고 저장하고 닫는다.
				BufferedWriter writer = new BufferedWriter(new FileWriter(filePath));
				writer.write(wordListView.toJSONArray().toJSONString());
				writer.close();
			}
			catch (IOException e1)
			{
				e1.printStackTrace();
			}
		}

		// 파일경로가 정해져 있지 않고 파일열기 대화상자를 열고 열기버튼을 눌렀으면
		else if (chooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION)
		{
			// 파일경로를 설정하고 다시 저장한다.
			filePath = chooser.getSelectedFile().getPath() + ".voca";
			save();
		}
	}
}

/**
 * 단어 리스트뷰
 */
class WordListView extends JScrollPane
{
	private final ArrayList<Word> words = new ArrayList<Word>(); // 단어목록
	private final JPanel list;

	/**
	 * 생성자
	 */
	public WordListView()
	{
		list = new JPanel();

		list.setLayout(new BoxLayout(list, BoxLayout.Y_AXIS));
	}

	/**
	 * 단어를 추가하는 메서드
	 * @param word : 추가할 단어
	 */
	public void addWord(final Word word)
	{
		words.add(word);
		final JPanel wordPanel = word.toPanel();

		wordPanel.addMouseListener(new MouseAdapter()
		{
			private boolean isClicked = false;

			@Override
			public void mouseClicked(MouseEvent e)
			{
				if (isClicked == false)
				{
					wordPanel.setBackground(new Color(0, 170, 255));
					isClicked = true;
					word.selected = true;
				}
				else
				{
					wordPanel.setBackground(new Color(255, 255, 255));
					isClicked = false;
					word.selected = false;
				}
			}
		});
		list.add(wordPanel);

		JSeparator separator = new JSeparator(SwingConstants.HORIZONTAL);
		separator.setForeground(Color.gray);
		Dimension d = separator.getPreferredSize();
		d.width = separator.getMaximumSize().width;
		separator.setMaximumSize(d);
		list.add(separator);

		setViewportView(list);
	}

	/**
	 * 단어를 삭제하는 메서드
	 * @param index : 삭제할 단어의 위치
	 */
	public void removeWord(int index)
	{
		try
		{
			words.remove(index);
			list.remove(2 * index);
			list.remove(2 * index);
			setViewportView(list);
		}
		catch (Exception e)
		{
		}
	}

	/**
	 * 사용자가 선택한 단어를 모두 지우는 메서드
	 */
	public void removeAllSelectedWord()
	{
		for (int i = words.size() - 1; i >= 0; i--)
		{
			Word word = words.get(i);
			if (word.selected)
				removeWord(i);
		}
	}

	/**
	 * 모든 단어를 지우는 메서드
	 */
	public void removeAllWord()
	{
		for (int i = words.size() - 1; i >= 0; i--)
			removeWord(i);
	}

	/**
	 * 단어목록을 JSONArray로 바꾸는 메서드
	 * @return : JSONArray
	 */
	public JSONArray toJSONArray()
	{
		JSONArray array = new JSONArray();
		for (Word i : words)
			array.add(i.toJson());

		return array;
	}

	/**
	 * 단어를 가져오는 메서드
	 * @param index : 가져올 단어의 위치
	 * @return : 단어
	 */
	public Word getWord(int index)
	{
		return words.get(index);
	}
}